"""
配置管理器模块

统一管理应用程序的所有配置文件，包括主配置、验证配置和TL配比配置。
支持配置文件的加载、验证、合并和自动生成默认配置。
"""

import os
import yaml
from pathlib import Path
from typing import Dict, Any, Optional, List, Union
from dataclasses import dataclass
import logging

from .default_configs import get_all_default_configs


logger = logging.getLogger(__name__)


@dataclass
class ConfigFile:
    """配置文件信息类"""
    name: str
    path: str
    required: bool = True
    config_type: str = "main"


class ConfigManager:
    """
    配置管理器类
    
    负责加载和管理所有类型的配置文件，提供统一的配置访问接口。
    支持配置文件优先级处理和默认配置生成。
    """
    
    def __init__(self, base_path: Optional[str] = None):
        """
        初始化配置管理器
        
        Args:
            base_path (Optional[str]): 配置文件基础路径，默认为项目根目录
        """
        self.base_path = Path(base_path) if base_path else Path.cwd()
        self.configs: Dict[str, Dict[str, Any]] = {}
        self.config_files: List[ConfigFile] = []
        self.default_configs = get_all_default_configs()
        
        # 定义配置文件列表
        self._define_config_files()
        
        # 加载所有配置
        self._load_all_configs()
    
    def _define_config_files(self) -> None:
        """定义系统使用的配置文件列表"""
        self.config_files = [
            ConfigFile(
                name="main_config",
                path=str(self.base_path / "config.yaml"),
                required=True,
                config_type="main"
            ),
            ConfigFile(
                name="validation_config", 
                path=str(self.base_path / "config" / "validation_config.yaml"),
                required=False,
                config_type="validation"
            ),
            ConfigFile(
                name="tl_ratio_config",
                path=str(self.base_path / "config" / "tl_ratio_config.yaml"),
                required=False,
                config_type="tl_ratio"
            )
        ]
    
    def _load_all_configs(self) -> None:
        """加载所有配置文件"""
        for config_file in self.config_files:
            try:
                self._load_config_file(config_file)
            except Exception as e:
                if config_file.required:
                    logger.error(f"加载必需配置文件失败: {config_file.path}, 错误: {e}")
                    raise
                else:
                    logger.warning(f"加载可选配置文件失败: {config_file.path}, 使用默认配置. 错误: {e}")
                    self._use_default_config(config_file)
    
    def _load_config_file(self, config_file: ConfigFile) -> None:
        """
        加载单个配置文件
        
        Args:
            config_file (ConfigFile): 配置文件信息
        """
        config_path = Path(config_file.path)
        
        if not config_path.exists():
            if config_file.required:
                logger.info(f"必需配置文件不存在，创建默认配置: {config_file.path}")
                self._create_default_config_file(config_file)
            else:
                logger.info(f"可选配置文件不存在，使用默认配置: {config_file.path}")
                self._use_default_config(config_file)
                return
        
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                config_data = yaml.safe_load(f) or {}
            
            # 验证配置格式
            self._validate_config_format(config_data, config_file)
            
            # 合并默认配置
            merged_config = self._merge_with_default(config_data, config_file.config_type)
            
            self.configs[config_file.name] = merged_config
            logger.info(f"成功加载配置文件: {config_file.path}")
            
        except yaml.YAMLError as e:
            raise ValueError(f"配置文件格式错误 {config_file.path}: {e}")
        except Exception as e:
            raise ValueError(f"加载配置文件失败 {config_file.path}: {e}")
    
    def _create_default_config_file(self, config_file: ConfigFile) -> None:
        """
        创建默认配置文件
        
        Args:
            config_file (ConfigFile): 配置文件信息
        """
        config_path = Path(config_file.path)
        
        # 确保目录存在
        config_path.parent.mkdir(parents=True, exist_ok=True)
        
        # 获取默认配置
        default_config = self.default_configs.get(config_file.config_type, {})
        
        try:
            with open(config_path, 'w', encoding='utf-8') as f:
                yaml.safe_dump(
                    default_config, 
                    f, 
                    default_flow_style=False,
                    allow_unicode=True, 
                    indent=2,
                    sort_keys=False
                )
            
            self.configs[config_file.name] = default_config.copy()
            logger.info(f"成功创建默认配置文件: {config_file.path}")
            
        except Exception as e:
            raise ValueError(f"创建默认配置文件失败 {config_file.path}: {e}")
    
    def _use_default_config(self, config_file: ConfigFile) -> None:
        """
        使用默认配置（不创建文件）
        
        Args:
            config_file (ConfigFile): 配置文件信息
        """
        default_config = self.default_configs.get(config_file.config_type, {})
        self.configs[config_file.name] = default_config.copy()
        logger.info(f"使用默认配置: {config_file.name}")
    
    def _validate_config_format(self, config_data: Dict[str, Any], config_file: ConfigFile) -> None:
        """
        验证配置文件格式
        
        Args:
            config_data (Dict[str, Any]): 配置数据
            config_file (ConfigFile): 配置文件信息
        """
        if not isinstance(config_data, dict):
            raise ValueError(f"配置文件必须是字典格式: {config_file.path}")
        
        # 根据配置类型进行特定验证
        if config_file.config_type == "main":
            self._validate_main_config(config_data)
        elif config_file.config_type == "validation":
            self._validate_validation_config(config_data)
        elif config_file.config_type == "tl_ratio":
            self._validate_tl_ratio_config(config_data)
    
    def _validate_main_config(self, config_data: Dict[str, Any]) -> None:
        """验证主配置文件格式"""
        required_sections = ["data_sources", "output", "algorithm"]
        for section in required_sections:
            if section not in config_data:
                raise ValueError(f"主配置文件缺少必需的节: {section}")
    
    def _validate_validation_config(self, config_data: Dict[str, Any]) -> None:
        """验证验证配置文件格式"""
        required_sections = ["projects", "resources", "tasks"]
        for section in required_sections:
            if section not in config_data:
                raise ValueError(f"验证配置文件缺少必需的节: {section}")
    
    def _validate_tl_ratio_config(self, config_data: Dict[str, Any]) -> None:
        """验证TL配比配置文件格式"""
        required_sections = ["tl_ratio_rules"]
        for section in required_sections:
            if section not in config_data:
                raise ValueError(f"TL配比配置文件缺少必需的节: {section}")
    
    def _merge_with_default(self, config_data: Dict[str, Any], config_type: str) -> Dict[str, Any]:
        """
        将用户配置与默认配置合并
        
        Args:
            config_data (Dict[str, Any]): 用户配置数据
            config_type (str): 配置类型
            
        Returns:
            Dict[str, Any]: 合并后的配置
        """
        default_config = self.default_configs.get(config_type, {})
        return self._deep_merge(default_config.copy(), config_data)
    
    def _deep_merge(self, base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
        """
        深度合并两个字典
        
        Args:
            base (Dict[str, Any]): 基础字典
            override (Dict[str, Any]): 覆盖字典
            
        Returns:
            Dict[str, Any]: 合并后的字典
        """
        for key, value in override.items():
            if key in base and isinstance(base[key], dict) and isinstance(value, dict):
                base[key] = self._deep_merge(base[key], value)
            else:
                base[key] = value
        return base
    
    def get_config(self, config_name: str, key_path: Optional[str] = None, default: Any = None) -> Any:
        """
        获取配置值
        
        Args:
            config_name (str): 配置名称 (main_config, validation_config, tl_ratio_config)
            key_path (Optional[str]): 配置键路径，使用点号分隔，如 'data_sources.projects_file'
            default (Any): 默认值
            
        Returns:
            Any: 配置值
        """
        if config_name not in self.configs:
            logger.warning(f"配置不存在: {config_name}")
            return default
        
        config = self.configs[config_name]
        
        if key_path is None:
            return config
        
        # 解析键路径
        keys = key_path.split('.')
        value = config
        
        try:
            for key in keys:
                if isinstance(value, dict) and key in value:
                    value = value[key]
                else:
                    return default
            return value
        except Exception:
            return default
    
    def set_config(self, config_name: str, key_path: str, value: Any) -> None:
        """
        设置配置值
        
        Args:
            config_name (str): 配置名称
            key_path (str): 配置键路径
            value (Any): 配置值
        """
        if config_name not in self.configs:
            self.configs[config_name] = {}
        
        keys = key_path.split('.')
        config = self.configs[config_name]
        
        # 导航到目标位置
        for key in keys[:-1]:
            if key not in config:
                config[key] = {}
            config = config[key]
        
        # 设置值
        config[keys[-1]] = value
    
    def reload_config(self, config_name: Optional[str] = None) -> None:
        """
        重新加载配置
        
        Args:
            config_name (Optional[str]): 配置名称，如果为None则重新加载所有配置
        """
        if config_name is None:
            # 重新加载所有配置
            self.configs.clear()
            self._load_all_configs()
        else:
            # 重新加载指定配置
            config_file = next((cf for cf in self.config_files if cf.name == config_name), None)
            if config_file:
                self._load_config_file(config_file)
            else:
                raise ValueError(f"未知的配置名称: {config_name}")
    
    def save_config(self, config_name: str, file_path: Optional[str] = None) -> None:
        """
        保存配置到文件
        
        Args:
            config_name (str): 配置名称
            file_path (Optional[str]): 文件路径，如果为None则使用原路径
        """
        if config_name not in self.configs:
            raise ValueError(f"配置不存在: {config_name}")
        
        # 确定保存路径
        if file_path is None:
            config_file = next((cf for cf in self.config_files if cf.name == config_name), None)
            if not config_file:
                raise ValueError(f"无法确定配置文件路径: {config_name}")
            file_path = config_file.path
        
        save_path = Path(file_path)
        save_path.parent.mkdir(parents=True, exist_ok=True)
        
        try:
            with open(save_path, 'w', encoding='utf-8') as f:
                yaml.safe_dump(
                    self.configs[config_name],
                    f,
                    default_flow_style=False,
                    allow_unicode=True,
                    indent=2,
                    sort_keys=False
                )
            logger.info(f"成功保存配置文件: {file_path}")
        except Exception as e:
            raise ValueError(f"保存配置文件失败 {file_path}: {e}")
    
    def get_all_configs(self) -> Dict[str, Dict[str, Any]]:
        """
        获取所有配置
        
        Returns:
            Dict[str, Dict[str, Any]]: 所有配置的字典
        """
        return self.configs.copy()
    
    def validate_all_configs(self) -> Dict[str, List[str]]:
        """
        验证所有配置的完整性
        
        Returns:
            Dict[str, List[str]]: 验证结果，键为配置名称，值为错误信息列表
        """
        validation_results = {}
        
        for config_name, config_data in self.configs.items():
            errors = []
            
            try:
                config_file = next((cf for cf in self.config_files if cf.name == config_name), None)
                if config_file:
                    self._validate_config_format(config_data, config_file)
            except Exception as e:
                errors.append(str(e))
            
            validation_results[config_name] = errors
        
        return validation_results
    
    def get_config_file_paths(self) -> Dict[str, str]:
        """
        获取所有配置文件路径
        
        Returns:
            Dict[str, str]: 配置名称到文件路径的映射
        """
        return {cf.name: cf.path for cf in self.config_files}
    
    def create_missing_config_files(self) -> List[str]:
        """
        创建缺失的配置文件
        
        Returns:
            List[str]: 创建的配置文件路径列表
        """
        created_files = []
        
        for config_file in self.config_files:
            config_path = Path(config_file.path)
            if not config_path.exists():
                try:
                    self._create_default_config_file(config_file)
                    created_files.append(config_file.path)
                except Exception as e:
                    logger.error(f"创建配置文件失败 {config_file.path}: {e}")
        
        return created_files


# 全局配置管理器实例
_config_manager: Optional[ConfigManager] = None


def get_config_manager(base_path: Optional[str] = None) -> ConfigManager:
    """
    获取全局配置管理器实例
    
    Args:
        base_path (Optional[str]): 配置文件基础路径
        
    Returns:
        ConfigManager: 配置管理器实例
    """
    global _config_manager
    
    if _config_manager is None:
        _config_manager = ConfigManager(base_path)
    
    return _config_manager


def reload_global_config() -> None:
    """重新加载全局配置"""
    global _config_manager
    if _config_manager:
        _config_manager.reload_config()


def get_config(config_name: str, key_path: Optional[str] = None, default: Any = None) -> Any:
    """
    便捷方法：获取配置值
    
    Args:
        config_name (str): 配置名称
        key_path (Optional[str]): 配置键路径
        default (Any): 默认值
        
    Returns:
        Any: 配置值
    """
    manager = get_config_manager()
    return manager.get_config(config_name, key_path, default)